package inteligenciaartificial;

public class Individuo implements Comparable<Individuo> {

    public final static int CantidadDeGenes = 36;
    //este arreglo contiene los valores de cada gen del individuo de la siguiente manera
    //posicion 0 a 8 valores para el producto 1, 9 a 17 valores para el producto 2, etc.
    //la primera posicion de cada intervalo de 9 genes representa la cantidad de producto
    // las siguientes representan las cantidades de materia prima que este utiliza.
    private int[] genes;

    //identifica univocamnete a cada individuo
    private int nroGeneracion;
    private int nroIndividuo;
    //para saber como fue obtenido
    private Operador operadorGenerador;
    
    //para identificar al padre
    private int nroGeneracionPadre;
    private int nroIndividuoPadre;
    
    //para identificar a la madre
    private int nroGeneracionMadre;
    private int nroIndividuoMadre;
    
    
    public Individuo(int[] genes, int generacion, int individuo, Individuo padre, Individuo madre, Operador operador){
        this.genes= genes;
        this.nroGeneracion= generacion;
        this.nroIndividuo= individuo;
        this.nroGeneracionPadre= padre.getNroGeneracion();
        this.nroIndividuoPadre= padre.getNroIndividuoPadre();
        if(madre!= null){
            this.nroGeneracionMadre= madre.getNroGeneracionMadre();
            this.nroIndividuoMadre= madre.getNroIndividuoMadre();
        }
        this.operadorGenerador= operador;
    }

    public Individuo(int[] genes){
        this.genes= genes;
        this.nroGeneracion= 0;
        this.nroIndividuo= 0;
        this.nroGeneracionPadre= 0;
        this.nroIndividuoMadre=0;
        this.nroGeneracionMadre= 0;
        this.nroIndividuoMadre= 0;
        this.operadorGenerador= Operador.Desconocido;
    }

    public int[] getGenes() {
            return genes;
    }

    public void setGenes(int[] genes) {
            this.genes = genes;
    }

    public int getGen(int nroDeGen){
            if(nroDeGen>CantidadDeGenes) return 0;
            return this.getGenes()[nroDeGen];
    }

    public int getCantidadProducto(int nroDeProducto){
            if (nroDeProducto>4) return 0;
            switch (nroDeProducto){
                    case 1: return this.getGen(0);
                    case 2: return this.getGen(9);
                    case 3: return this.getGen(18);
                    case 4: return this.getGen(27);
                    default: return 0;
            }
    }

    public int getCantidadMaterial(int nroDeProducto, int nroDeMaterial){
            switch (nroDeProducto){
            case 1: return this.getGen(nroDeMaterial);
            case 2: return this.getGen(9+nroDeMaterial);
            case 3: return this.getGen(18+nroDeMaterial);
            case 4: return this.getGen(27+nroDeMaterial);
            default: return 0;
            }
    }

    @Override
    public String toString(){
            StringBuilder string = new StringBuilder();
            string.append("Individuo: ");
            string.append(this.nroIndividuo);
//            string.append(" Generacion: ");
//            string.append(this.nroGeneracion);
            string.append(" Genes: ");
            for(int i=0; i<CantidadDeGenes; i++){
                    if(i%9==0 && i!=0){
                            string.append(" | ");
                    }
                    if(i%9!=0){
                            string.append(", ");
                    }
                    string.append(this.getGen(i));
            }
            string.append(". Individuo padre: ");
            string.append(this.nroIndividuoPadre);
//            string.append(" GenPadre: ");
//            string.append(this.nroGeneracionPadre);
            string.append(". Individuo madre: ");
            string.append(this.nroIndividuoMadre);
//            string.append(" GenMadre: ");
//            string.append(this.nroGeneracionMadre);
            string.append(". Operador: ");
            string.append(this.operadorGenerador);
            return string.toString();
    }
    
    /**
     * @return the nroGeneracion
     */
    public int getNroGeneracion() {
        return nroGeneracion;
    }

    /**
     * @return the nroIndividuo
     */
    public int getNroIndividuo() {
        return nroIndividuo;
    }

    /**
     * @return the operadorGenerador
     */
    public Operador getOperadorGenerador() {
        return operadorGenerador;
    }

    /**
     * @return the nroGeneracionPadre
     */
    public int getNroGeneracionPadre() {
        return nroGeneracionPadre;
    }

    /**
     * @return the nroIndividuoPadre
     */
    public int getNroIndividuoPadre() {
        return nroIndividuoPadre;
    }

    /**
     * @return the nroGeneracionMadre
     */
    public int getNroGeneracionMadre() {
        return nroGeneracionMadre;
    }

    /**
     * @return the nroIndividuoMadre
     */
    public int getNroIndividuoMadre() {
        return nroIndividuoMadre;
    }

    /**
     * @param nroGeneracion the nroGeneracion to set
     */
    public void setNroGeneracion(int nroGeneracion) {
        this.nroGeneracion = nroGeneracion;
    }

    /**
     * @param nroIndividuo the nroIndividuo to set
     */
    public void setNroIndividuo(int nroIndividuo) {
        this.nroIndividuo = nroIndividuo;
    }

    /**
     * @param operadorGenerador the operadorGenerador to set
     */
    public void setOperadorGenerador(Operador operadorGenerador) {
        this.operadorGenerador = operadorGenerador;
    }

    /**
     * @param nroGeneracionPadre the nroGeneracionPadre to set
     */
    public void setNroGeneracionPadre(int nroGeneracionPadre) {
        this.nroGeneracionPadre = nroGeneracionPadre;
    }

    /**
     * @param nroIndividuoPadre the nroIndividuoPadre to set
     */
    public void setNroIndividuoPadre(int nroIndividuoPadre) {
        this.nroIndividuoPadre = nroIndividuoPadre;
    }

    /**
     * @param nroGeneracionMadre the nroGeneracionMadre to set
     */
    public void setNroGeneracionMadre(int nroGeneracionMadre) {
        this.nroGeneracionMadre = nroGeneracionMadre;
    }

    /**
     * @param nroIndividuoMadre the nroIndividuoMadre to set
     */
    public void setNroIndividuoMadre(int nroIndividuoMadre) {
        this.nroIndividuoMadre = nroIndividuoMadre;
    }
    
    //Para ordenar de forma ascendente
    @Override
    public int compareTo(Individuo individuoAComparar) {
        return AptitudUtilidad.calcularAptitud(this) - AptitudUtilidad.calcularAptitud(individuoAComparar);
    }
    
    //compara si dos individuos son iguales dadas sus cantidaddes de productos
    public boolean individuosIguales(Individuo ind){
        boolean iguales= true;
        
        for(int i=1;i<5;i++){
            if(this.getCantidadProducto(i)!= ind.getCantidadProducto(i)) iguales= false;
        }
        
        return iguales;
    }
    
    public boolean tieneMadre(){
        if(operadorGenerador==Operador.CruzaBinomial ||
           operadorGenerador==Operador.CruzaMultipunto ||
           operadorGenerador==Operador.CruzaSimple){
            return true;
        }
        return false;
    }
    
    public enum Operador{
        SeleccionElitista,
        SeleccionPorRanking,
        SeleccionPorRuleta,
        SeleccionPorTorneo,
        SeleccionPorCopiasEsperadas,
        CruzaSimple,
        CruzaMultipunto,
        CruzaBinomial,
        MutacionPorTempAscendente,
        MutacionPorTempDescendente,
        Mutacion,
        Desconocido
    }
    
}


